package xyz.zhouxf.rpc.transport;

import lombok.extern.slf4j.Slf4j;
import xyz.zhouxf.rpc.annotation.Service;
import xyz.zhouxf.rpc.annotation.ServiceScan;
import xyz.zhouxf.rpc.enumeration.RpcError;
import xyz.zhouxf.rpc.exception.RpcException;
import xyz.zhouxf.rpc.provider.ServiceProvider;
import xyz.zhouxf.rpc.registry.ServiceRegistry;
import xyz.zhouxf.rpc.serializer.RpcSerializer;
import xyz.zhouxf.rpc.util.ReflectUtil;

import java.net.InetSocketAddress;
import java.util.Set;

/**
 * @author zhouxf
 * @date 2022/9/26
 */
@Slf4j
public abstract class AbstractRpcServer implements RpcServer {

    protected String host;
    protected int port;

    protected ServiceRegistry serviceRegistry;
    protected ServiceProvider serviceProvider;

    protected RpcSerializer serializer;

    public void scanService() {
        String mainStackTrace = ReflectUtil.getStackTrace();
        Class<?> mainClass;
        try {
            mainClass = Class.forName(mainStackTrace);
            if(!mainClass.isAnnotationPresent(ServiceScan.class)) {
                log.error("启动类没有 @ServiceScan");
                throw new RpcException(RpcError.SERVICE_SCAN_NOT_FOUND);
            }
        } catch (ClassNotFoundException e) {
            log.error("未知错误");
            throw new RpcException(RpcError.UNKNOWN_ERROR);
        }
        String packagePath = mainClass.getAnnotation(ServiceScan.class).value();

        if("".equals(packagePath)) {
            packagePath = mainStackTrace.substring(0, mainStackTrace.lastIndexOf('.'));
        }
        Set<Class<?>> classes = ReflectUtil.getClasses(packagePath);

        for(Class<?> clazz : classes) {
            if(clazz.isAnnotationPresent(Service.class)) {
                String serviceName = clazz.getAnnotation(Service.class).name();
                Object service;
                try {
                    service = clazz.newInstance();
                } catch (InstantiationException | IllegalAccessException e) {
                    log.error("实例化 {} 时出现错误",clazz.getName());
                    continue;
                }
                if("".equals(serviceName)) {
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for(Class<?> interfaceClass : interfaces) {
                        publishService(service, interfaceClass.getName());
                    }
                }else {
                    publishService(service, serviceName);
                }
            }
        }

    }

    @Override
    public <T> void publishService(T service, String serviceName) {
        serviceProvider.addService(service, serviceName);
        serviceRegistry.register(serviceName, new InetSocketAddress(host, port));
    }
}
